package com.sy.simpleegg.serialport.whmandroid

import com.sy.simpleegg.ext.logFile
import com.sy.simpleegg.serialport.bean.ComData
import com.sy.simpleegg.serialport.whmandroid.bean.WhmAndroidCheckBean
import com.sy.simpleegg.serialport.whmandroid.bean.WhmAndroidCoinOrderBean
import com.sy.simpleegg.serialport.whmandroid.bean.WhmAndroidOutCoinsBean
import com.sy.simpleegg.serialport.whmandroid.bean.WhmAndroidOutResultBean
import com.sy.simpleegg.serialport.whmandroid.bean.WhmAndroidSaveCoinsBean
import com.sy.simpleegg.serialport.whmandroid.bean.WhmAndroidSaveResultBean
import com.sy.simpleegg.serialport.whmandroid.cash.CashForeignParser
import com.sy.simpleegg.serialport.whmandroid.cash.CashParser
import com.sy.simpleegg.serialport.whmandroid.status.WhmAndroidOutFlowStatus
import com.sy.simpleegg.serialport.whmandroid.status.WhmAndroidOutResult
import com.sy.simpleegg.serialport.whmandroid.status.WhmAndroidSaveFlowStatus
import com.sy.simpleegg.serialport.whmandroid.status.WhmAndroidSaveResult
import com.sy.simpleegg.serialport.whmandroid.status.WhmAndroidSnStatus
import com.sy.simpleegg.serialport.whmandroid.util.WhmAndroidStatusUtil
import com.sy.simpleegg.util.ByteUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.cnbleu.serialport.SerialPort
import java.util.Queue
import java.util.UUID
import java.util.concurrent.LinkedBlockingDeque
import kotlin.random.Random

class WhmAndroidCoinController(
    cashType: Int,//1-中国 2-国外
    portName: String,
    baudrate: SerialPort.BAUDRATE,
    stopb: SerialPort.STOPB,
    datab: SerialPort.DATAB,
    parity: SerialPort.PARITY,
    runHeartBeat: Boolean,
    verNumber: Int = 1,
    speed: Long = 10L
) : BaseWhmAndroidController(portName, baudrate, stopb, datab, parity, verNumber, speed) {

    private val TAG = javaClass.simpleName

    private var dispenser1Open = false//投币器1 0-关 1-开
    private var dispenser2Open = false//投币器1 0-关 1-开

    private var inCoins1 = 0L
    private var inCoins2 = 0L

    private var charArr = arrayOf("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "C", "D", "E", "F")

    override fun onDispenserResp(dispenser1Coins: String, dispenser2Coins: String) {
        logFile("存币响应：dispenser1Coins=$dispenser1Coins dispenser2Coins=$dispenser2Coins")
        val dp1Coins = dispenser1Coins.toLong(16)
        val dp2Coins = dispenser2Coins.toLong(16)
        if (dp1Coins > 0 && !handling){
            inCoins1 += dp1Coins
            serialControllerListener?.onDispenser1Resp(inCoins1)
            serialControllerListener?.onInCoins(inCoins1, if (dispenser2Open) inCoins2 else 0)
        }else if (dp1Coins > 0){
            whmAndroidSaveFlowStatus = WhmAndroidSaveFlowStatus.RESP
            serialControllerListener?.onDispenser1SaveResp(dp1Coins)
        }

//        if (dp2Coins > 0 && !handling){
//            inCoins2 += dp2Coins
//            serialControllerListener?.onDispenser2Resp(inCoins2)
//            serialControllerListener?.onInCoins(if (dispenser1Open) inCoins1 else 0, inCoins2)
//        }else if (dp2Coins > 0){
//            whmAndroidSaveFlowStatus = WhmAndroidSaveFlowStatus.RESP
//            serialControllerListener?.onDispenser2SaveResp(dp2Coins)
//        }
        //投币器2有投币，需要出币处理
        if (dp2Coins > 0){
            serialControllerListener?.onDispenser2SaveResp(dp2Coins)
        }

        currentWhmAndroidSaveCoinsBean?.let {
            it.dispenser1Coins = it.dispenser1Coins + dp1Coins
//            it.dispenser2Coins = it.dispenser2Coins + dp2Coins
            logFile("存币响应 改变存币数据 投币器1=${it.dispenser1Coins} 投币器2=${it.dispenser2Coins}")
        }
    }

    override fun onDispenserRec(dispenser1Enable: String, dispenser2Enable: String) {
        if (!initDispenser) initDispenser = true
        currentWhmAndroidSaveCoinsBean?.let {
            whmAndroidSaveFlowStatus = if (dispenser1Enable == "00"){
                WhmAndroidSaveFlowStatus.FINISH
            }else{
                WhmAndroidSaveFlowStatus.REC
            }
        }
    }

    override fun onOutResp(
        snStatus: String,
        motor1Status: String,
        motor1NeedOutCoins: String,
        motor1RealOutCoins: String,
        motor2Status: String,
        motor2NeedOutCoins: String,
        motor2RealOutCoins: String
    ) {
        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.RESP
        outResp = true
        currentWhmAndroidOutCoinsBean?.let {
            it.whmAndroidSnStatus = WhmAndroidStatusUtil.getSnStatus(snStatus.toInt(16))
            it.motor1Status = WhmAndroidStatusUtil.getMotorStatus(motor1Status.toInt(16))
            it.motor1RealOutCoins = motor1RealOutCoins.toLong(16)
            logFile("出币信息：马达1出币数=${currentWhmAndroidOutCoinsBean?.motor1RealOutCoins}")
            it.motor2Status = WhmAndroidStatusUtil.getMotorStatus(motor2Status.toInt(16))
            it.motor2RealOutCoins = motor2RealOutCoins.toLong(16)
            logFile("出币信息：马达2出币数=${currentWhmAndroidOutCoinsBean?.motor2RealOutCoins}")
        }

        currentWhmAndroidOutCoinsBean?.let {

//            when (it.motor1Status){
//                MotorStatus.ABNORMAL -> {
//                    serialControllerListener?.onMotorErr(1)
//                }
//                MotorStatus.FAULT -> {
//                    serialControllerListener?.onMotorErr(1)
//                }
//                else -> {}
//            }
//            when (it.motor2Status){
//                MotorStatus.ABNORMAL -> {
//                    serialControllerListener?.onMotorErr(2)
//                }
//                MotorStatus.FAULT -> {
//                    serialControllerListener?.onMotorErr(2)
//                }
//                else -> {}
//            }
        }
    }

    override fun onOutRec(
        sn: String,
        motor1NeedOutCoins: String,
        motor2NeedOutCoins: String,
        snStatus: String,
        errCode: String
    ) {
        logFile("接收出币订单：sn=$sn motor1NeedOutCoins=$motor1NeedOutCoins motor2NeedOutCoins=$motor2NeedOutCoins snStatus=$snStatus errCode=$errCode")
        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.REC
//        val remainCount = motor1NeedOutCoins.toLong(16) + motor2NeedOutCoins.toLong(16)
//        val totalNeedOutCoins = currentOutCoinsBean?.motor1NeedOutCoins!! + currentOutCoinsBean?.motor2NeedOutCoins!!
//        val totalRealOutCoins = currentOutCoinsBean?.motor1RealOutCoins!! + currentOutCoinsBean?.motor2RealOutCoins!!
//        val remainCount = totalNeedOutCoins-totalRealOutCoins
        currentWhmAndroidOutCoinsBean?.whmAndroidSnStatus = WhmAndroidStatusUtil.getSnStatus(snStatus.toInt(16))
//        when (StatusUtil.getSnStatus(snStatus.toInt(16))){
//            SnStatus.SHIPPING_COMPLETED -> {
//                if (outType == 1){
//                    serialControllerListener?.outCoinFinish(remainCount, totalRealOutCoins, true)
//                }else if (outType == 2){
//                    serialControllerListener?.onClearCoin(true, totalRealOutCoins)
//                }
//            }
//            SnStatus.SHIPPING_DENIED -> {
//                if (outType == 1){
//                    serialControllerListener?.outCoinFinish(remainCount, totalRealOutCoins, true)
//                }else if (outType == 2){
//                    serialControllerListener?.onClearCoin(true, totalRealOutCoins)
//                }
//            }
//            SnStatus.SHIPPING_ERROR -> {
//                if (outType == 1){
//                    serialControllerListener?.outCoinFinish(remainCount, totalRealOutCoins, true)
//                }else if (outType == 2){
//                    serialControllerListener?.onClearCoin(true, totalRealOutCoins)
//                }
//            }
//            else -> {
//                serialControllerListener?.onOutRec()
//            }
//        }
    }

    override fun onCheckedResp(devStatus: String, motor1Status: String, motor2Status: String) {
        state = false
        whmAndroidCheckBean = WhmAndroidCheckBean(devStatus, WhmAndroidStatusUtil.getMotorStatus(motor1Status.toInt(16)), WhmAndroidStatusUtil.getMotorStatus(motor2Status.toInt(16)))
    }

    override fun onBanknoteResp(stateHex: String, cashDataHex: String) {
//        serialControllerListener?.onBanknoteResp(stateHex, cashDataHex)
        when (stateHex){
            "01" -> {
                cashParser1?.onDataRec(cashDataHex)
                cashForeignParser1?.onDataRec(cashDataHex)
            }
            "02" -> {
                cashParser2?.onDataRec(cashDataHex)
                cashForeignParser2?.onDataRec(cashDataHex)
            }
        }
    }

    override fun onMotorConfigResp(
        forwardTimeoutHex: String,
        reverseTimeoutHex: String,
        stopDelayHex: String
    ) {
        serialControllerListener?.onMotorConfigResp(forwardTimeoutHex, reverseTimeoutHex, stopDelayHex)
    }

    /**
     * 心跳间隔，正常-10秒 异常-3秒
     */
    private val HEARTBEAT_INTERVAL_CONNECT: Long = 10 * 1000
    /**
     * 心跳间隔，正常-10秒 异常-3秒
     */
    private val HEARTBEAT_INTERVAL_DISCONNECT: Long = 3 * 1000

    /**
     * 马达1状态 0-正常 1-故障
     */
    private var motor1State = 0
    /**
     * 马达2状态 0-正常 1-故障
     */
    private var motor2State = 0
    /**
     * 是否出币结束
     */
    private var isOutFinish: Boolean = true

    /**
     * 协程
     */
    private var coroutineScope: CoroutineScope? = null
    /**
     * 控制板心跳线程
     */
    private var heartBeatJob: Job? = null

    /**
     * 心跳响应状态，发心跳指令前先设置为false，收到心跳响应设置为true
     */
    private var state: Boolean = true
    private var stateCode = 0
    private var errCode = 0

    /**
     * 链接状态
     */
    private var isConnect = false

    private val orderQueue: Queue<WhmAndroidCoinOrderBean> = LinkedBlockingDeque<WhmAndroidCoinOrderBean>()
    private var handleJob: Job? = null
    private var isLoop = true
    private var default_timeout = 10*1000
    private var save_timeout = 61*1000
    private var whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.PREPARE
    private var whmAndroidSaveFlowStatus = WhmAndroidSaveFlowStatus.PREPARE

    private var outResp = false
    private var handling = false

    private var currentWhmAndroidOutCoinsBean: WhmAndroidOutCoinsBean? = null
    private var currentWhmAndroidSaveCoinsBean: WhmAndroidSaveCoinsBean? = null
    private var whmAndroidCheckBean: WhmAndroidCheckBean? = null

    private var cashParser1: CashParser? = null
    private var cashParser2: CashParser? = null
    private var cashForeignParser1: CashForeignParser? = null
    private var cashForeignParser2: CashForeignParser? = null

    private var initDispenser = false

//    private var currentOutSn = ""
//    private var m1NeedOutCoins = 0L
//    private var m2NeedOutCoins = 0L
//    private var m1RealOutCoins = 0L
//    private var m2RealOutCoins = 0L

    init {
        logFile("打开自研控制板，纸钞机类型=$cashType 串口号=$portName 波特率=$baudrate 停止位=$stopb 数据位=$datab 校验位=$parity 控制板心跳：${if (runHeartBeat) "开启" else "关闭"}")
        coroutineScope = MainScope()
        initHandleJob()
        if (runHeartBeat) heartBeatLoop()

        initCashParse(cashType)

        coroutineScope?.launch {
            delay(1000)
            do {
                saveCoinClose()
                delay(1000)
            }while (!initDispenser)
        }
    }

    private fun initCashParse(type: Int){
        try {
            when (type){
                1 -> {
                    cashParser1 = CashParser(coroutineScope!!, object : CashParser.CashParseCallback{
                        override fun sendData(dataHex: String) {
                            sendBanknoteData("01", dataHex)
                        }

                        override fun getMoney(checkMoney: Long, totalMoney: Long) {
                            serialControllerListener?.getMoney1(checkMoney, totalMoney)
                        }

                        override fun recieveMoney(tempMoney: Long, checkMoney: Long) {
                            serialControllerListener?.recieveMoney1(tempMoney, checkMoney)
                        }
                    })

                    cashParser2 = CashParser(coroutineScope!!, object : CashParser.CashParseCallback{
                        override fun sendData(dataHex: String) {
                            sendBanknoteData("02", dataHex)
                        }

                        override fun getMoney(checkMoney: Long, totalMoney: Long) {
                            serialControllerListener?.getMoney2(checkMoney, totalMoney)
                        }

                        override fun recieveMoney(tempMoney: Long, checkMoney: Long) {
                            serialControllerListener?.recieveMoney2(tempMoney, checkMoney)
                        }
                    })
                }
                else -> {
                    cashForeignParser1 = CashForeignParser(coroutineScope!!, object : CashForeignParser.CashParseCallback{
                        override fun sendData(dataHex: String) {
                            sendBanknoteData("01", dataHex)
                        }

                        override fun getMoney(checkMoney: Long, totalMoney: Long) {
                            serialControllerListener?.getMoney1(checkMoney, totalMoney)
                        }

                        override fun recieveMoney(tempMoney: Long, checkMoney: Long) {
                            serialControllerListener?.recieveMoney1(tempMoney, checkMoney)
                        }
                    })

                    cashForeignParser2 = CashForeignParser(coroutineScope!!, object : CashForeignParser.CashParseCallback{
                        override fun sendData(dataHex: String) {
                            sendBanknoteData("02", dataHex)
                        }

                        override fun getMoney(checkMoney: Long, totalMoney: Long) {
                            serialControllerListener?.getMoney2(checkMoney, totalMoney)
                        }

                        override fun recieveMoney(tempMoney: Long, checkMoney: Long) {
                            serialControllerListener?.recieveMoney2(tempMoney, checkMoney)
                        }
                    })
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
        }
    }

    fun getConnectState(): Boolean{
        return isConnect
    }

    /**
     * 释放资源
     */
    fun release(){
        releaseBase()
        close()
        isLoop = false
        coroutineScope?.cancel()
    }

    /**
     * 设置马达状态
     */
    fun setMotorState(m1State: Boolean, m2State: Boolean){
        motor1State = if (m1State) 0 else 1
        motor2State = if (m2State) 0 else 1
    }

    private fun initHandleJob(){
        handleJob?.cancel()

        handleJob = coroutineScope?.launch (Dispatchers.IO){
            while (isLoop){
                try {
                    run checkSize@{
                        if (orderQueue.size > 0 && !handling) {
                            var orderBean: WhmAndroidCoinOrderBean? = null
                            while (orderQueue.poll().also { orderBean = it } != null) {
                                handling = true
                                val sn = orderBean!!.sn
                                val amount = orderBean!!.amount
                                val m1Coins = orderBean!!.m1Coins
                                val m2Conis = orderBean!!.m2Conis
                                val type = orderBean!!.type
                                val saveCoinType = orderBean!!.saveType

                                if (!isConnect){
//                                    serialControllerListener.onOutCoinsErr()
                                    handling = false
                                    return@checkSize
                                }

                                when (type){
                                    1 -> {
                                        val result = outCoinsHandler(sn, amount, m1Coins, m2Conis)
//                                        val totalNeedOutCoins = result.outCoinsBean!!.motor1NeedOutCoins + result.outCoinsBean!!.motor2NeedOutCoins
//                                        val totalRealOutCoins = result.outCoinsBean!!.motor1RealOutCoins + result.outCoinsBean!!.motor2RealOutCoins
//                                        val remainCount = totalNeedOutCoins - totalRealOutCoins
//                                        withContext(Dispatchers.Main){
//                                            serialControllerListener?.outCoinFinish(remainCount, totalRealOutCoins, true)
//                                            serialControllerListener?.onOutResult(when (result.resultCode){
//                                                OutResult.COMPLETED -> "出币完成"
//                                                OutResult.REFUSE -> "拒绝出币"
//                                                OutResult.ERROR -> "出币异常"
//                                                OutResult.TIMEOUT -> "出币超时"
//                                            })
//                                        }

                                        result.whmAndroidOutCoinsBean?.let {
                                            val totalNeedOutCoins = it.motor1NeedOutCoins + it.motor2NeedOutCoins
                                            val totalRealOutCoins = it.motor1RealOutCoins + it.motor2RealOutCoins
                                            val remainCount = totalNeedOutCoins - totalRealOutCoins
                                            withContext(Dispatchers.Main){
                                                serialControllerListener?.outCoinFinish(remainCount, totalRealOutCoins, true)
                                                serialControllerListener?.onOutResult(when (result.resultCode){
                                                    WhmAndroidOutResult.COMPLETED -> "出币完成"
                                                    WhmAndroidOutResult.REFUSE -> "拒绝出币"
                                                    WhmAndroidOutResult.ERROR -> "出币异常"
                                                    WhmAndroidOutResult.TIMEOUT -> "出币超时"
                                                })
                                            }
                                        }

//                                        when (result.resultCode){
//                                            OutResult.COMPLETED -> {}
//                                            OutResult.REFUSE -> {}
//                                            OutResult.ERROR -> {}
//                                            OutResult.TIMEOUT -> {}
//                                        }
                                    }
                                    2 -> {
                                        val saveResult = saveCoinsHandler(saveCoinType)
                                        saveResult.whmAndroidSaveCoinsBean?.let {
                                            val realSaveCoins = it.dispenser1Coins + it.dispenser2Coins
                                            withContext(Dispatchers.Main){
                                                serialControllerListener?.saveCoinFinish(realSaveCoins)
                                            }
                                        }
                                        currentWhmAndroidSaveCoinsBean = null
                                        when (saveResult.resultCode){
                                            WhmAndroidSaveResult.FINISH -> {}
                                            WhmAndroidSaveResult.TIMEOUT -> {
                                                saveCoinClose()
                                            }
                                            WhmAndroidSaveResult.ERROR -> {
                                                saveCoinClose()
                                            }
                                        }
                                    }
                                    3 -> {
                                        val clearResult = clearCoinsHandler(sn, amount, m1Coins, m2Conis)
                                        val realOutCoins = clearResult.whmAndroidOutCoinsBean!!.motor1RealOutCoins + clearResult.whmAndroidOutCoinsBean!!.motor2RealOutCoins
                                        refreshClearCoins(true, realOutCoins)
                                    }
                                    else -> {

                                    }
                                }

                                //清空粘包数据缓存
                                clearStickyData()
                                handling = false
                            }
                        }
                    }
                }catch (e: Exception){
                    e.printStackTrace()
                    logFile("处理出币点单异常：${e.message}")
                }
            }
        }
    }

    private fun heartBeatLoop(){
        try {
            heartBeatJob?.cancel()

            heartBeatJob = coroutineScope?.launch (Dispatchers.IO){
                try {
                    run breaking@{
                        while (true){
                            //出币中，不发送心跳指令，直接返回心跳正常
                            if (handling) {
//                                isConnect = true
                                serialControllerListener?.heartBeat(isConnect, stateCode, errCode)
                                delay(5000)
                                return@breaking
                            }

                            state = true
                            checkState()
                            delay(500)
                            isConnect = !state
                            serialControllerListener?.heartBeat(isConnect, stateCode, errCode)

                            if (state){
                                delay(HEARTBEAT_INTERVAL_DISCONNECT)
                            }else{
                                delay(HEARTBEAT_INTERVAL_CONNECT)
                            }
                        }
                    }
                }catch (e: Exception){
                    e.printStackTrace()
                    logFile("心跳处理异常2：" + e.message)
                }
            }
        }catch (e: Exception){
            e.printStackTrace()
            logFile("心跳处理异常：" + e.message)
        }
    }

    private suspend fun outCoinsHandler(sn: String, amount: Long, m1Coins: Long, m2Coins: Long): WhmAndroidOutResultBean {
        return try {
            //指令响应超时
            var overCount = 0
            val interval = 100L
            val maxCount = default_timeout / interval
            var outFinish = false

            whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.PREPARE

            currentWhmAndroidOutCoinsBean = WhmAndroidOutCoinsBean(
                sn,
                WhmAndroidStatusUtil.getSnStatus(-1),
                amount,
                WhmAndroidStatusUtil.getMotorStatus(-1),
                m1Coins,
                0,
                WhmAndroidStatusUtil.getMotorStatus(-1),
                m2Coins,
                0)

            var lastOutCoins = -1L

            outCoin(sn, amount, m1Coins, m2Coins)

            var isRec = false
            val result = run result@{
                while (true){
                    delay(interval)
                    overCount ++
                    when (whmAndroidOutFlowStatus){
                        WhmAndroidOutFlowStatus.PREPARE -> {

                        }
                        WhmAndroidOutFlowStatus.REC -> {
                            currentWhmAndroidOutCoinsBean?.run {
                                when (whmAndroidSnStatus){
                                    WhmAndroidSnStatus.SHIPPING_COMPLETED -> {
                                        outFinish = true
                                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.FINISH
                                        return@result WhmAndroidOutResult.COMPLETED
                                    }
                                    WhmAndroidSnStatus.SHIPPING_DENIED -> {
                                        outFinish = true
                                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.FINISH
                                        return@result WhmAndroidOutResult.REFUSE
                                    }
                                    WhmAndroidSnStatus.SHIPPING_ERROR -> {
                                        outFinish = true
                                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.FINISH
                                        return@result WhmAndroidOutResult.ERROR
                                    }
                                    else -> {
                                        if (!isRec) {
                                            isRec = true
                                            serialControllerListener?.onOutRec()
                                        }
                                    }
                                }
                            }
                        }
                        WhmAndroidOutFlowStatus.RESP -> {
                            currentWhmAndroidOutCoinsBean?.run {
                                when (whmAndroidSnStatus){
                                    WhmAndroidSnStatus.SHIPPING_COMPLETED -> {
                                        outFinish = true
                                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.FINISH
                                        return@result WhmAndroidOutResult.COMPLETED
                                    }
                                    WhmAndroidSnStatus.SHIPPING_DENIED -> {
                                        outFinish = true
                                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.FINISH
                                        return@result WhmAndroidOutResult.REFUSE
                                    }
                                    WhmAndroidSnStatus.SHIPPING_ERROR -> {
                                        outFinish = true
                                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.FINISH
                                        return@result WhmAndroidOutResult.ERROR
                                    }
                                    else -> {
                                        if (outResp){
                                            outResp = false
                                            overCount = 0

                                            val realOutCoins = motor1RealOutCoins + motor2RealOutCoins
                                            logFile("realOutCoins=$realOutCoins")
                                            if (lastOutCoins != realOutCoins){
                                                lastOutCoins = realOutCoins
                                                refreshOutCoins(realOutCoins, motor1NeedOutCoins + motor2NeedOutCoins - realOutCoins)
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        WhmAndroidOutFlowStatus.FINISH -> {

                        }
                        WhmAndroidOutFlowStatus.TIMEOUT -> {

                        }
                    }

                    if (!outFinish && overCount >= maxCount){
                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.TIMEOUT
                        return@result WhmAndroidOutResult.TIMEOUT
                    }
                }
                WhmAndroidOutResult.TIMEOUT
            }

            delay(500)
            logFile("出币结束：马达1出币数=${currentWhmAndroidOutCoinsBean?.motor1RealOutCoins} 马达2出币数=${currentWhmAndroidOutCoinsBean?.motor2RealOutCoins}")
            return WhmAndroidOutResultBean(result, currentWhmAndroidOutCoinsBean)
        }catch (e: Exception){
            e.printStackTrace()
            logFile("出币流程异常：" + e.message)
            WhmAndroidOutResultBean(WhmAndroidOutResult.ERROR, null)
        }
    }

    private suspend fun clearCoinsHandler(sn: String, amount: Long, m1Coins: Long, m2Coins: Long): WhmAndroidOutResultBean{
        return try {
            //指令响应超时
            var overCount = 0
            val interval = 500L
            val maxCount = default_timeout / interval
            var outFinish = false

            whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.PREPARE

            currentWhmAndroidOutCoinsBean = WhmAndroidOutCoinsBean(
                sn,
                WhmAndroidStatusUtil.getSnStatus(-1),
                amount,
                WhmAndroidStatusUtil.getMotorStatus(-1),
                m1Coins,
                0,
                WhmAndroidStatusUtil.getMotorStatus(-1),
                m2Coins,
                0)
            var lastOutCoins = -1L

            outCoin(sn, amount, m1Coins, m2Coins)

            var isRec = false
            val result = run result@{
                while (true){
                    delay(interval)
                    overCount ++
                    when (whmAndroidOutFlowStatus){
                        WhmAndroidOutFlowStatus.PREPARE -> {

                        }
                        WhmAndroidOutFlowStatus.REC -> {
                            currentWhmAndroidOutCoinsBean?.run {
                                when (whmAndroidSnStatus){
                                    WhmAndroidSnStatus.SHIPPING_COMPLETED -> {
                                        outFinish = true
                                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.FINISH
                                        return@result WhmAndroidOutResult.COMPLETED
                                    }
                                    WhmAndroidSnStatus.SHIPPING_DENIED -> {
                                        outFinish = true
                                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.FINISH
                                        return@result WhmAndroidOutResult.REFUSE
                                    }
                                    WhmAndroidSnStatus.SHIPPING_ERROR -> {
                                        outFinish = true
                                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.FINISH
                                        return@result WhmAndroidOutResult.ERROR
                                    }
                                    else -> {
                                        if (!isRec) {
                                            isRec = true
                                            serialControllerListener?.onOutRec()
                                        }
                                    }
                                }
                            }
                        }
                        WhmAndroidOutFlowStatus.RESP -> {
                            currentWhmAndroidOutCoinsBean?.run {

                                when (whmAndroidSnStatus){
                                    WhmAndroidSnStatus.SHIPPING_COMPLETED -> {
                                        outFinish = true
                                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.FINISH
                                        return@result WhmAndroidOutResult.COMPLETED
                                    }
                                    WhmAndroidSnStatus.SHIPPING_DENIED -> {
                                        outFinish = true
                                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.FINISH
                                        return@result WhmAndroidOutResult.REFUSE
                                    }
                                    WhmAndroidSnStatus.SHIPPING_ERROR -> {
                                        outFinish = true
                                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.FINISH
                                        return@result WhmAndroidOutResult.ERROR
                                    }
                                    else -> {
                                        if (outResp){
                                            outResp = false
                                            overCount = 0

                                            val realOutCoins = motor1RealOutCoins + motor2RealOutCoins
                                            if (lastOutCoins != realOutCoins){
                                                lastOutCoins = realOutCoins
                                                refreshClearCoins(false, realOutCoins)
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        WhmAndroidOutFlowStatus.FINISH -> {

                        }
                        WhmAndroidOutFlowStatus.TIMEOUT -> {

                        }
                    }

                    if (!outFinish && overCount >= maxCount){
                        whmAndroidOutFlowStatus = WhmAndroidOutFlowStatus.TIMEOUT
                        return@result WhmAndroidOutResult.TIMEOUT
                    }
                }
                WhmAndroidOutResult.TIMEOUT
            }

            return WhmAndroidOutResultBean(result, currentWhmAndroidOutCoinsBean)
        }catch (e: Exception){
            e.printStackTrace()
            logFile("出币流程异常：" + e.message)
            WhmAndroidOutResultBean(WhmAndroidOutResult.ERROR, null)
        }
    }

    /**
     * 存币处理
     * @param orderNumber 订单号
     * @param saveCoinType 0-双投币器 1-投币器1 2-投币器2
     */
    private suspend fun saveCoinsHandler(saveCoinType: Int): WhmAndroidSaveResultBean{
        return try {
            logFile("开始 存币处理")
            //指令响应超时
            var overCount = 0
            val interval = 500L
            val maxCount = save_timeout / interval

            whmAndroidSaveFlowStatus = WhmAndroidSaveFlowStatus.PREPARE

            currentWhmAndroidSaveCoinsBean = WhmAndroidSaveCoinsBean()

            var lastSaveCoins = -1L
            var isRec = false

//            saveEnable(true)
//            when (saveCoinType){
//                0 -> {
////                    dispenser1Open(true)
////                    delay(1000)
////                    dispenser2Open(true)
//                    dispenserAllOpen(true)
//                }
//                1 -> {
//                    dispenser1Open(true)
//                    delay(1000)
//                    dispenser2Open(false)
//                }
//                2 -> {
//                    dispenser1Open(false)
//                    delay(1000)
//                    dispenser2Open(true)
//                }
//            }
            dispenserSave(true, false)
//            startInCoin(saveCoinType, true)

            val result = run result@{
                while (overCount <= maxCount){
                    delay(interval)

                    when (whmAndroidSaveFlowStatus){
                        WhmAndroidSaveFlowStatus.PREPARE -> {
                            overCount ++
                            if (overCount >= maxCount){
                                return@result WhmAndroidSaveResult.TIMEOUT
                            }
                        }
                        WhmAndroidSaveFlowStatus.REC -> {
                            logFile("存币准备数据")
                            if (isRec){
                                overCount ++
                            }else{
                                overCount = 0
                                isRec = true
                                currentWhmAndroidSaveCoinsBean?.let {
                                    val totalSaveCoins = it.dispenser1Coins + it.dispenser2Coins
                                    if (totalSaveCoins != lastSaveCoins){
                                        lastSaveCoins = totalSaveCoins
                                        serialControllerListener?.onCoinRefresh(-1, totalSaveCoins, false)
                                    }
                                }
                            }
                        }
                        WhmAndroidSaveFlowStatus.RESP -> {
                            logFile("存币响应数据")
                            currentWhmAndroidSaveCoinsBean?.let {
                                val totalSaveCoins = it.dispenser1Coins + it.dispenser2Coins
                                if (totalSaveCoins != lastSaveCoins){
                                    overCount = 0
                                    lastSaveCoins = totalSaveCoins
                                    serialControllerListener?.onCoinRefresh(-1, totalSaveCoins, false)
                                }else{
                                    overCount ++
                                }
                            }
                        }

                        WhmAndroidSaveFlowStatus.FINISH -> {
                            return@result WhmAndroidSaveResult.FINISH
                        }
                    }
                }
                WhmAndroidSaveResult.TIMEOUT
            }

            return WhmAndroidSaveResultBean(result, currentWhmAndroidSaveCoinsBean)
        }catch (e: Exception){
            e.printStackTrace()
            logFile("存币流程异常：" + e.message)
            WhmAndroidSaveResultBean(WhmAndroidSaveResult.ERROR, null)
        }
    }

    private suspend fun refreshOutCoins(realOutCoins: Long, remainCoins: Long){
        withContext(Dispatchers.Main){
            serialControllerListener?.onCoinRefresh(realOutCoins, remainCoins, true)
        }
    }

    private suspend fun refreshClearCoins(isFinish: Boolean, realOutCoins: Long){
        withContext(Dispatchers.Main){
            serialControllerListener?.onClearCoin(isFinish, realOutCoins)
        }
    }

    /**
     * 校验出币数量
     */
    private fun checkOutCount(count: Long):Boolean{
        if (count <= 0) serialControllerListener?.countErr(count)
        return count > 0
    }



   private fun outCoins(snHex: String, amount: Long, coins1: Long, coins2: Long){
        if (handling){
            return
        }
        orderQueue.add(WhmAndroidCoinOrderBean(1, getSnHex(), amount, coins1, coins2))
    }

    fun outCoinM1Business(coins: Long, amount: Long = 100L){
        val sn = UUID.randomUUID().toString().replace("-", "").trim()

        outCoins(sn, amount, coins, 0)
    }

    fun outCoinM2Business(coins: Long, amount: Long = 100L){
        val sn = UUID.randomUUID().toString().replace("-", "").trim()
        outCoins(sn, amount, 0, coins)
    }

    fun outCoinAlternately(coins: Long, amount: Long = 100L){
        val sn = UUID.randomUUID().toString().replace("-", "").trim()
        var coins1 = 0L
        var coins2 = 0L
        when(coins){
            1L -> {
                coins1 = 1L
                coins2 = 0L
            }
            else -> {
                if (coins % 2L == 0L){
                    //偶数
                    coins1 = coins / 2
                    coins2 = coins / 2
                }else{
                    //奇数
                    coins1 = (coins - 1) / 2 + 1;
                    coins2 = (coins - 1) / 2;
                }
            }
        }
        outCoins(sn, amount, coins1, coins2)
    }

    fun clearCoinAlternately(){
        if (handling){
            return
        }
        val coins1 = 65535L
        val coins2 = 65535L
        val amount = coins1*100 + coins2*100
        val sn = UUID.randomUUID().toString().replace("-", "").trim()
        orderQueue.add(WhmAndroidCoinOrderBean(3, getSnHex(), amount, coins1, coins2))
    }

    fun clearCoins(){
        if (handling){
            return
        }
        val coins1 = 65535L
        val coins2 = 65535L
        val amount = coins1*100 + coins2*100
        val sn = UUID.randomUUID().toString().replace("-", "").trim()
        orderQueue.add(WhmAndroidCoinOrderBean(3, getSnHex(), amount, coins1, coins2))
    }

    /**
     * 存币
     * @param open true-打开 false-关闭
     */
    fun saveCoins(open: Boolean){
        if (open) {
            if (handling) {
                return
            }
            logFile("Android版本 存币开启")
            orderQueue.add(WhmAndroidCoinOrderBean(2, "", 0, 0, 0, 0))
        }else{
            handling = false

            saveCoinClose()
        }
    }

    private fun saveCoinClose(){
        dispenser1Open = false
        dispenser2Open = true
        whmAndroidSaveFlowStatus = WhmAndroidSaveFlowStatus.FINISH
        saveController(0, 1)
//        saveEnable(false)
    }

    /**
     * 投币器1开关
     */
    private fun dispenser1Open(open: Boolean){
        if (open == dispenser1Open){
            return
        }
        //重置进币数
        if (open) inCoins1 = 0
        dispenser1Open = open
        inCoins(open, dispenser2Open)
    }

    /**
     * 投币器2开关
     */
    private fun dispenser2Open(open: Boolean){
        if (open == dispenser2Open){
            return
        }
        //重置进币数
        if (open) inCoins2 = 0
        dispenser2Open = open
        inCoins(dispenser1Open, open)
    }

    /**
     *投币器开关
     */
    private fun dispenserAllOpen(open: Boolean){
        if (open == dispenser2Open && open == dispenser1Open){
            return
        }
        //重置进币数
        if (open) {
            inCoins1 = 0
            inCoins2 = 0
        }
        dispenser1Open = open
        dispenser2Open = open
        inCoins(open, open)
    }

    private fun dispenserSave(open1: Boolean, open2: Boolean){
//        if (open1 == dispenser1Open && open2 == dispenser1Open){
//            return
//        }
        //重置进币数
        if (open1) {
            inCoins1 = 0
        }
        if (open2) {
            inCoins2 = 0
        }
        dispenser1Open = open1
        dispenser2Open = open2
        inCoins(open1, open2)
    }

    private fun inCoins(open1: Boolean, open2: Boolean){
        saveController(if (open1) 1 else 0, if (open2) 1 else 0)
    }

    fun getMotorParam(){
        getMotorConfig()
    }

    fun setMotorParam(f: Int, r: Int, s: Int){
        setMotorConfig(f, r, s)
    }

    fun startInMoney(number: Int, open: Boolean){
        when (number){
            1 -> {
                cashParser1?.startInMoney(open)
                cashForeignParser1?.startInMoney(open)
            }
            2 -> {
                cashParser2?.startInMoney(open)
                cashForeignParser2?.startInMoney(open)
            }
        }
    }

    /**
     * 校验纸钞后，决定 进钞或者拒绝进钞
     */
    fun canSaveMoney(number: Int, save: Boolean){
        when (number){
            1 -> {
                cashParser1?.canSaveMoney(save)
                cashForeignParser1?.canSaveMoney(save)
            }
            2 -> {
                cashParser2?.canSaveMoney(save)
                cashForeignParser2?.canSaveMoney(save)
            }
        }
    }

    fun banknoteInit(number: Int){
        val numberHex = ByteUtil.int2HexStr(number, 2, false)!!
        sendBanknoteData(numberHex, "02")
    }

    /**
     * 打开或关闭投币器进币
     * @param type 0-所有投币器 1-投币器1 2-投币器2
     * @param open true-开 false-关
     */
    fun startInCoin(type: Int, open: Boolean){
        when (type){
            1 -> dispenser1Open(open)
            2 -> dispenser2Open(open)
            0 -> dispenserAllOpen(open)
        }
    }

    /**
     * 重置马达状态
     * 清币后或者故障后需要重置
     */
    fun resetMotor(){
        setMotorState(0, 0)
    }

    private fun getSnHex(): String{
        var snHex = ""
        for (i in 0..63){
            val random = Random.nextInt(charArr.size)
            snHex += charArr[random]
        }
        return snHex
    }

    override fun cmdTimeout(comData: ComData) {
        logFile("指令响应超时：${comData.data} ")
    }

//    override fun sendCmd(msg: String) {
//        logFile("发送指令：$msg")
//    }

    private var serialControllerListener: SerialControllerListener? = null
    interface SerialControllerListener{
        /**
         * 心跳数据回调
         */
        fun heartBeat(isConnect: Boolean, stateCode: Int, errCode: Int)

        /**
         * 出币数异常回调
         */
        fun countErr(count: Long)

        /**
         * 马达出币超时回到
         */
        fun motorTimeout(motorNumber: Int)

        /**
         * 清币回调
         */
        fun onClearCoin(clearFinish: Boolean, clearCoinCount: Long)

        /**
         * 出币数据回调
         */
        fun outCoinFinish(remainCount: Long, currentOutCount: Long, outFinish: Boolean)

        /**
         * 马达故障
         */
        fun onMotorErr(motorNumber: Int)

        /**
         * 存币结束
         */
        fun saveCoinFinish(count: Long)

        /**
         * 刷新出币或存币数据
         */
        fun onCoinRefresh(coinCount: Long, remainCoins: Long, outOrSave: Boolean)

        /**
         * 控制板接收订单
         */
        fun onOutRec()

        /**
         * 出币结果
         */
        fun onOutResult(msg: String)

        fun onBanknoteResp(stateHex: String, cashDataHex: String)

        fun onMotorConfigResp(forwardTimeoutHex: String, reverseTimeoutHex: String, stopDelayHex: String)

        /**
         * 进钞
         * @param checkMoney 当前进钞的面额
         * @param totalMoney 总进钞面额
         */
        fun getMoney1(checkMoney: Long, totalMoney: Long)

        /**
         * 校验金额是否超过剩余币数或其他逻辑，根据继承者处理进钞或拒绝
         * @param tempMoney
         * @param checkMoney
         */
        fun recieveMoney1(tempMoney: Long, checkMoney: Long)

        /**
         * 进钞
         * @param checkMoney 当前进钞的面额
         * @param totalMoney 总进钞面额
         */
        fun getMoney2(checkMoney: Long, totalMoney: Long)

        /**
         * 校验金额是否超过剩余币数或其他逻辑，根据继承者处理进钞或拒绝
         * @param tempMoney
         * @param checkMoney
         */
        fun recieveMoney2(tempMoney: Long, checkMoney: Long)

        fun onDispenser1Resp(coins: Long)

        fun onDispenser2Resp(coins: Long)

        fun onDispenser1SaveResp(coins: Long)

        fun onDispenser2SaveResp(coins: Long)

        fun onInCoins(coins1: Long, coins2: Long)
    }

    fun setSerialControllerListener(listener: SerialControllerListener){
        this.serialControllerListener = listener
    }

}